﻿﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace NetworkSimulator
{
    public class Node
    {
        private int id;

        public int Id
        {
            get { return id; }
        }

        private List<Link> links;

        public List<Link> Links
        {
            get { return this.links; }
            set { this.links = value; }
        }

        private Queue<Request> requestQueue;

        private Queue<Request> rerouteQueue;

        private Thread thread;

        private Routing router;

        private LinkManager linkManager;

        // Create new stopwatch
        Stopwatch stopwatch;

        public Node(int id)
        {
            this.id = id;
            links = new List<Link>();
            requestQueue = new Queue<Request>();
            rerouteQueue = new Queue<Request>();
            linkManager = LinkManager.instance();
            stopwatch = new Stopwatch();
            thread = new Thread(new ThreadStart(this.process));
            thread.Priority = ThreadPriority.Normal;
            thread.Start();
        }

        public void addLink(Link link)
        {
            links.Add(link);
        }

        public void recieveRequest(Request request)
        {
            lock (requestQueue)
            {
                requestQueue.Enqueue(request);
            }
        }

        public void rerouteRequest(Request request)
        {
            lock (rerouteQueue)
            {
                rerouteQueue.Enqueue(request);
                rerouteCount++;
            }
        }

        public static int acceptedCount = 0;
        public static int rejectedCount = 0;
        public static int rerouteCount = 0;
        public static int reroutedCount = 0;

        public void process()
        {
            while (thread.IsAlive)
            {
                if (router == null)
                {
                    router = new MHA();
                    router.getPath(new Request(0, 0, 0, 0, -1, -1));
                }

                lock (rerouteQueue)
                {
                    if (rerouteQueue.Count > 0)
                    {
                        // ====== Synchronize =====

                        // ========================

                        Request request = rerouteQueue.Dequeue();
                        //Console.WriteLine(request);
                        Path path;
                        lock (Topology.lockingObject)
                        {
                            stopwatch.Restart();
                            path = router.getPath(request);
                            request.Path = path;
                            stopwatch.Stop();
                            // allocateBandwidth(path, request.Bandwidth); //<-- LinkManager will do this
                        }
                        if (path.Links.Count > 0)
                            reroutedCount++;
                        //Console.WriteLine("RES-" + request.Id + ":" + path + " computing time: " + stopwatch.Elapsed.TotalMilliseconds + "ms");
                        linkManager.serveRequest(request);
                    }
                }

                lock (requestQueue)
                {
                    if (requestQueue.Count > 0)
                    {
                        // ====== Synchronize =====
                            
                        // ========================

                        Request request = requestQueue.Dequeue();
                        //Console.WriteLine(request);
                        Path path;
                        lock (Topology.lockingObject)
                        {
                            stopwatch.Restart();
                            path = router.getPath(request);
                            request.Path = path;
                            stopwatch.Stop();
                            // allocateBandwidth(path, request.Bandwidth); //<-- LinkManager will do this
                        }
                        if (path.Links.Count > 0)
                            acceptedCount++;
                        else
                            rejectedCount++;
                        //Console.WriteLine("RES-" + request.Id + ":" + path + " computing time: " + stopwatch.Elapsed.TotalMilliseconds + "ms");
                        linkManager.serveRequest(request);
                    }
                }
                Thread.Sleep(1);
            }
        }

        //private Release makeRelease(Request request, Path path)
        //{
        //    return new Release(request.Id, path, request.Bandwidth, request.HoldingTime);
        //}

        //private void allocateBandwidth(Path path, double bandwidth)
        //{
        //    foreach (Link link in path.Links)
        //    {
        //        link.UsingBandwidth += bandwidth;
        //    }
        //}
    }
}